package tcptunnel

import (
	"context"
	log "github.com/cihub/seelog"
	"github.com/songgao/water"
	"io"
	"net"
	"strconv"
	"strings"
	"sync"
	"time"
	"tunnel/authentication"
	cache "tunnel/cache"
	"tunnel/common/config"
	"tunnel/pool"
	"tunnel/traffic"
	vtunnel "tunnel/tunnel"
)

//
// TCPServerV3
// @Description:
//
type TCPServerV3 struct {
	lock    sync.Mutex
	IFace   *water.Interface
	Config  config.Config
	Context context.Context
	Cancel  context.CancelFunc
	Error   error
	//auth       *authentication.AuthServer
	authServer *authentication.AuthServerV2
	//cache   *cache.Cache
	tunnels map[string]*pool.MultiConn
	//ipTable *cache.IpTable
	ipTable *cache.IpTableV2
}

//
// NewServerV3
// @Description: 持久化多连接模型
// @return *TCPServerV3
//
func NewServerV3() *TCPServerV3 {
	return &TCPServerV3{
		Config: config.Current,
	}
}

//
// Init
// @Description:
// @receiver s
// @return error
//
func (s *TCPServerV3) Init() error {
	//s.auth = authentication.NewServer(s.Config.Auth, &TCPAuthHandler{Server: s})
	s.authServer = authentication.NewServerV2(s.Config.Auth, &TCPAuthServerHandler{Server: s})
	ctx, cancelFunc := context.WithCancel(context.Background())
	s.Context = ctx
	s.Cancel = cancelFunc
	//iface
	if s.IFace == nil {
		iface, err := vtunnel.CreateIFace(water.TUN)
		if err != nil {
			return err
		}
		err = vtunnel.SetupIFace(s.Config, iface)
		if err != nil {
			return err
		}
		s.IFace = iface
	}
	//cache
	//s.cache = cache.New(time.Minute*30, time.Minute*15)
	//s.ipTable = cache.NewIpTable()
	s.ipTable = cache.NewIpTableV2(time.Minute*30, time.Minute*15)
	s.tunnels = make(map[string]*pool.MultiConn)
	return nil
}

//
// Start
// @Description:
// @receiver s
// @return error
//
func (s *TCPServerV3) Start() error {
	//go s.auth.Start()
	go s.authServer.Start()
	go s.ConnectionHandler()
	go s.TXHandler()
	select {
	case <-s.Context.Done():
		err := s.Error
		s.Error = nil
		return err
	}
}

//
// Stop
// @Description:
// @receiver s
//
func (s *TCPServerV3) Stop() {
	s.Cancel()
}

//
// ConnectionHandler
// @Description:
// @receiver s
//
func (s *TCPServerV3) ConnectionHandler() {
	address := strings.Join([]string{s.Config.Global.Address, strconv.Itoa(s.Config.Global.Port)}, ":")
	//listener, err := net.Listen("tcp", address)
	tcpAddr, err := net.ResolveTCPAddr("tcp4", address)
	listener, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		s.Error = err
		s.Stop()
		return
	}
	log.Info("server listen on : ", address)
	for {
		select {
		case <-s.Context.Done():
			return
		default:
			conn, _ := listener.AcceptTCP()
			//conn, _ := listener.Accept()
			//_ = conn.SetNoDelay(false)
			//_ = conn.SetWriteBuffer(1024 * 1500)
			//_ = conn.SetReadBuffer(1024 * 1500)
			go s.RXHandler(conn)
		}
	}
}

//
// RXHandler
// @Description:
// @receiver s
// @param conn
//
func (s *TCPServerV3) RXHandler(conn net.Conn) {
	address := authentication.GetRemoteAddr(conn)
	defer func() {
		if conn != nil {
			_ = conn.Close()
		}
	}()
	buffer := make([]byte, s.Config.Global.MTU)
	//if s.auth.Check(address) {
	if s.authServer.Check(address) {
		//var num int
		num := -1
		s.lock.Lock()
		if m, ok := s.tunnels[address]; ok {
			num = m.Push(conn)
			//log.Info("[RX] 创建多连接: ", address, " #", m.Size)
			//num = m.Size
		} else {
			multiConn := pool.NewMultiConn(address)
			num = multiConn.Push(conn)
			s.tunnels[address] = multiConn
			//log.Info("[RX] 创建多连接: ", address, " #", multiConn.Size)
			//num = multiConn.Size
		}
		s.lock.Unlock()
		//log.Info("[tunnel->iface] 开始处理来自 ", address, " 的流量")
		for {
			n, err := conn.Read(buffer)
			//start := time.Now().Nanosecond()
			if err != nil {
				if err == io.EOF {
					//close from client
					//log.Info("[rx][", address, "][#", num, "] exit")
				} else if strings.Contains(err.Error(), errClosedStr) {
					//close from server
					//log.Info("[rx][", address, "][#", num, "] exit")
				} else if strings.Contains(err.Error(), errResetByPeer) {
					//close from client
				} else {
					log.Info("[rx][", address, "][#", num, "] exit with error ", err.Error())
				}
				break
			}
			//bytes := buffer[:n]
			//id_start := time.Now().Nanosecond()
			identification := traffic.IdentificationV2(buffer, traffic.In)
			if identification == "" {
				continue
			}
			//id_end := time.Now().Nanosecond()
			//cache_start := time.Now().Nanosecond()
			//s.cache.Set(identification, address, cache.DefaultExpiration)
			//cache_end := time.Now().Nanosecond()
			//TODO 流量处理
			s.ipTable.Set(identification, address)
			n, _ = s.IFace.Write(buffer[:n])
			//end := time.Now().Nanosecond()
			//log.Info("[tunnel->iface][", address, "#", num, "] ", n, " bytes")
			//log.Info("[tunnel->iface][total:", end-start, "ns | id:", id_end-id_start, "ns | cache:", cache_end-cache_start, "ns] ", n, " bytes")
		}
	} else {
		log.Info("[tunnel->iface] ", address, " 验证失败")
	}
}

//
// TXHandler
// @Description:
// @receiver s
//
func (s *TCPServerV3) TXHandler() {
	buffer := make([]byte, s.Config.Global.MTU)
	for {
		n, err := s.IFace.Read(buffer)
		//start := time.Now().Nanosecond()
		if err != nil || err == io.EOF || n == 0 {
			continue
		}
		//bytes := buffer[:n]
		//id_start := time.Now().Nanosecond()
		identification := traffic.IdentificationV2(buffer, traffic.Out)
		if identification == "" {
			//未能标识流量方向做丢包处理
			continue
		}
		//id_end := time.Now().Nanosecond()
		//cache_start := time.Now().Nanosecond()
		if address, ok := s.ipTable.Get(identification); ok {
			if m, ok := s.tunnels[address]; ok {
				//TODO 处理流量
				n, _ = m.Get().Write(buffer[:n])
			}
		}
		//log.Info("[iface->tunnel][total:", end-start, "ns | id:", id_end-id_start, "ns | cache:", cache_end-cache_start, "ns] ", n, " bytes")
	}
}
